如何使用React Hooks请求数据(精简译文) 您所在的位置:网站首页 掘金 react 18并发 如何使用React Hooks请求数据(精简译文)

如何使用React Hooks请求数据(精简译文)

2023-08-23 02:38| 来源: 网络整理| 查看: 265

原文链接:How to fetch data with React Hooks

前言:这篇文章是Dan推荐阅读的入门文章,作者讲的很详细,但对于有一定基础,急需做封装的人来说,则会显得有些啰嗦。于是乎,我想在这篇文章中,更精简地表达他的观点。

1. 使用React Hooks请求数据

这个组件使用了useState来进行数据管理,通过遍历data中的hits数组来进行数据渲染。当前的hits还是个空数组,所以接下来,我们将使用axios来这个库来请求数据。如果你还没有安装axios这个库,你可以先通过 npm intall axios 这行命令进行安装。(注:这里仅用axios这个库来做例子的展示,需要用什么库其实取决于你自己)

然而第一次写的时候,你可能会直接写出以上的代码。这段代码其实有两个问题,原文太啰嗦了,我就精简一下。第一点,useEffect必须返回一个cleanup函数,或者啥都不返回,如果用async声明这个函数的话,那么其实它返回的是一个Promise对象,这是不被允许的。你可以看到控制台报了这种警告。

useEffect function must return a cleanup function or nothing. Promises and useEffect(async () => ...) are not supported, but you can call an async function inside an effect..

如果你安装了hook相关eslint插件的话,还会给你这样的提示

其次,如果我们想要在组件渲染的时候,只请求一次的话,应该在useEffect的第二个参数中,加上空数组,这应该算是常识了,初步修改后的组件如下:

接下来,如果你对错误处理,加载指示器,如何在表单中触发获取数据,以及如何实现一个可重复使用的自定义hook感兴趣的话,就接着往下看。

2.如何以编程/手动的方式去触发hook

在上面的例子中,我们在组件渲染的过程中,触发了一次数据渲染。接下来我们将使用一个input元素,让我们的API请求能够根据input的输入值而发生改变。

接着我们给query进行动态的赋值

但这样就行了吗?当前的话,useEffect中的第二个元素为一个空数组,这就说明了它只在组件渲染后执行一次。如果我们需要根据query值的变化来触发这个effect的话,别忘了在第二个参数中加上对应的依赖,如图所示。

现在我们实现了,当input框中的值发生改变时,就能动态地去获取相关的数据信息,但是,如果我们想手动地触发请求呢?这个时候可以加一个按钮,当我们点击按钮时,再触发请求。

别忘了把url中的query,以及useEffect依赖的query变量替换成search

到这里,你有没有察觉到search和query这两个state其实是有些相似的,这容易让人感到疑惑,所以这里我们可以把search state改成url state。

这样,当你通过setUrl来改变url时,也会发起对应的请求,此时的url和query,所代表的含义和先前的query与search相比,更加容易让人理解了。

3. 在hooks中引入加载指示器(loading)

加loading其实非常简单,只需要多声明一个boolean类型的state即可,代码如下:

4. 在hooks中引入错误处理(error handling)

一般来说,我们在发起请求的时候,都会给这个请求包裹上try catch函数,那么我们引入一个错误标识就十分简单了,只需要在catch函数中,把对应的state设为false即可,代码如下:

5. 在form表单提交时发起请求

在form表单提交时发请求,其实也十分简单,但是有一个注意点就是,记得阻止事件的默认行为,否则在点击的时候你的页面将会被刷新。

6. 封装一个自定义请求数据的hook

除了query 是和input输入框相挂钩的state外,其它与请求相关的state,都可以封装在一个函数内,并return 所有需要在组件使用到的相关变量。

在组件中,我们可以这样去使用封装好的useHakerNewsApi

但是,当前的useHackerNewsApi,它的data和url都是写在hook里面的,如果如果我们初始化的data和url不同,那这个hook不就没用了嘛。其实这也很好解决,我们只需要把data和url变成传进来的参数即可。

这样,一个基本的fetch hook就封装好了,其实还是十分简单的,只要有些hook基础,基本都能看懂并且实现出来。

这里给出封装好的代码方便大家复制看效果。

import React, { Fragment, useState, useEffect } from 'react'; import axios from 'axios'; const useDataApi = (initialUrl, initialData) => { const [data, setData] = useState(initialData); const [url, setUrl] = useState(initialUrl); const [isLoading, setIsLoading] = useState(false); const [isError, setIsError] = useState(false); useEffect(() => { const fetchData = async () => { setIsError(false); setIsLoading(true); try { const result = await axios(url); setData(result.data); } catch (error) { setIsError(true); } setIsLoading(false); }; fetchData(); }, [url]); return [{ data, isLoading, isError }, setUrl]; }; function App() { const [query, setQuery] = useState('redux'); const [{ data, isLoading, isError }, doFetch] = useDataApi( 'https://hn.algolia.com/api/v1/search?query=redux', { hits: [] }, ); return ( { doFetch( `http://hn.algolia.com/api/v1/search?query=${query}`, ); event.preventDefault(); }} > setQuery(event.target.value)} /> Search {isError && Something went wrong ...} {isLoading ? ( Loading ... ) : ( {data.hits.map(item => ( {item.title} ))} )} ); } export default App 7. 使用useReducer对hook做出修改

在上面的hook例子中,我们定义了相关的state,但有些state,其实它们之间是存在相互关联的关系的,所以,我们可以想办法,把这些具有关联关系的state,给结合起来。这也是hook开发中一个比较常见的做法。那么useState和useReducer,到底用哪个呢。这里大家可以看看作者的另外一篇文章 useReducer vs useState in React ,作者在这个地方,认为使用useReducer的话,可以更好地使代码具有阅读性。

注意啦,useReducer需要你传入一个reducer function和一个initalState object,这里把isLoading,isError,data这三个相关联的state做了合并,并且当作initalState传入。

接下来,我们可以把hook中相关的逻辑,大致分为三个部分,分别是请求初始化,请求成功,请求失败。如图所示:

别忘了,把return的数组也要改一下,毕竟现在state做了合并,只需要导出一个state就够了,代码如下:

接下来,我们需要在reducer中去 实现 FETCH_INIT,FETCH_SUCCESS ,FETCH_FAILURE 对应的函数。实现上其实也不难,如果你对下面的代码有疑惑,那么说明你对useReducer还不够了解,需要再去官方文档补一补知识。

8. 如何中止数据请求

在写代码的过程中,如果在页面卸载的时候,依然去触发相关的setState操作,那么可能就会导致内存泄露。所以,为了防止组件在卸载的过程中,不再去触发对应的操作,我们可以对代码进行优化,代码如下:

完整代码已经被作者上传到github上了,可访问 github.com/the-road-to… 进行查看。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有